package top.zk123.chain.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.web.multipart.MultipartFile;
import top.zk123.chain.bean.*;
import top.zk123.chain.exception.FileEmptyException;
import top.zk123.chain.exception.FileUploadException;
import top.zk123.chain.exception.OCRFailedException;
import top.zk123.chain.exception.WrongFileTypeException;
import top.zk123.chain.shiro.TokenUtils;

import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 公开工具类
 *
 * @author Ke Zhange
 * @since 1.0
 */
public class GlobalUtils {
    //TODO: 部署服务器时,将文件上传路径改为 Tomcat 路径
    public static final String TOMCAT_PATH = "/home/zhangke/workspace/apache-tomcat-8.5.60/webapps/ROOT/src/";
//    public static final String TOMCAT_PATH = "C:/apache-tomcat-9.0.41/webapps/ROOT/src/";
    public static final String EXCEL_PATH = "chain/excel/";
    public static final String WEB_PATH = "https://www.zk123.top/src/";
    public static final String USER_PIC_PATH = "chain/userPic/";
    public static final String CERT_PIC_PATH = "chain/certPic/";
    public static final String AVATAR_PATH = "chain/avatar/";
    public static final String ID_CARD_PATH = "chain/idCard/";
    public static final String JSON_PATH = "chain/json/";


    /**
     * 上传单个Excel文件.
     *
     * @param file     文件
     * @param filePath 文件保存路径
     * @return 原文件名，更新后的文件名
     * @throws FileEmptyException     上传文件为空
     * @throws WrongFileTypeException 错误文件类型
     * @throws FileUploadException    文件上传失败
     */
    public static UploadPath fileUpload(MultipartFile file, String filePath) throws FileEmptyException,
            WrongFileTypeException, FileUploadException {
        String path;
        // 文件不为空
        if (file.isEmpty()) {
            throw new FileEmptyException();
        }
        // 获取文件后缀名
        String originFileName = file.getOriginalFilename();
        String extension = GlobalUtils.getExtension(Objects.requireNonNull(originFileName));
        // 仅支持 xlsx, jpg, png 上传
        if (!(extension.equals("xlsx") || extension.equals("png") || extension.equals("jpg"))) {
            throw new WrongFileTypeException();
        }
        // 更新文件名 (UUID.后缀)
        String newFileName = UUID.randomUUID().toString() + "." + extension;
        // 上传存储路径
        path = filePath + newFileName;
        File dest = new File(path);
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        try {
            // 文件写入
            file.transferTo(dest);
        } catch (IOException e) {
            throw new FileUploadException("文件上传失败");
        }
        return new UploadPath(originFileName, newFileName);
    }

    /**
     * 上传单张、多张图片.
     *
     * @param files    文件
     * @param filePath 文件保存路径
     * @return 列表(文件名.后缀)
     * @throws FileEmptyException     上传文件为空
     * @throws WrongFileTypeException 错误文件类型
     * @throws FileUploadException    文件上传失败
     */
    public static List<UploadPath> filesUpload(MultipartFile[] files, String filePath) throws
            FileUploadException, FileEmptyException, WrongFileTypeException {
        List<UploadPath> result = new ArrayList<>();
        int pos = 0;
        for (MultipartFile file : files) {
            if (!file.isEmpty()) {
                pos++;
                // 获取文件后缀名
                String extension;
                String originFileName = file.getOriginalFilename();
                extension = GlobalUtils.getExtension(Objects.requireNonNull(originFileName));
                // 仅支持 xlsx, jpg, png 上传
                if (!(extension.equals("xlsx") || extension.equals("png") || extension.equals("jpg") || extension.equals("json"))) {
                    throw new WrongFileTypeException();
                }
                try {
                    // 文件重命名 (UUID.后缀)
                    String newFileName = UUID.randomUUID().toString() + "." + extension;
                    // 上传存储路径
                    File dest = new File(filePath + newFileName);
                    if (!dest.getParentFile().exists()) {
                        dest.getParentFile().mkdirs();
                    }
                    // 写入文件
                    file.transferTo(dest);
                    result.add(new UploadPath(originFileName, newFileName));
                } catch (IOException e) {
                    throw new FileUploadException("第" + pos + "个文件上传失败");
                }
            } else {
                throw new FileEmptyException("第" + pos + "个文件上传失败,文件为空");
            }
        }
        return result;
    }

    /**
     * 将ExcelData 对象转化称为 Certificate 对象
     *
     * @param excelData {@link ExcelData}
     * @return {@link Certificate}
     */
    public static CertificateTmp ExcelData2CertificateTmp(ExcelData excelData) {
        CertificateTmp certificate = new CertificateTmp();
        certificate.setCertType(excelData.getCertType());
        //TODO: certState 当前状态默认为 0 - 未上链
        certificate.setName(excelData.getName());
        certificate.setSex(excelData.getSex());
        certificate.setBirth(excelData.getBirth());
        certificate.setUserId(excelData.getUserId());
        certificate.setAcademy(excelData.getAcademy());
        certificate.setMajor(excelData.getMajor());
        certificate.setEducation(excelData.getEducation());
        certificate.setAdmissionDate(excelData.getAdmissionDate());
        certificate.setGraduationDate(excelData.getGraduationDate());
        certificate.setCertId(excelData.getCertId());
        certificate.setIssueDate(excelData.getIssueDate());
        certificate.setInstitution(excelData.getInstitution());
        certificate.setUserPic(excelData.getUserPic());
        certificate.setCertPic(excelData.getCertPic());
        return certificate;
    }

    /**
     * @param fileName "xxx.后缀"
     * @return "后缀"
     * @since 2021-3-18
     */
    public static String getExtension(String fileName) {
        String extension = "";
        if (fileName == null || "".equals(fileName)) {
            throw new NullPointerException();
        }
        int i = fileName.lastIndexOf(".");
        if (i > 0) {
            extension = fileName.substring(i + 1);
        }
        return extension;
    }

    /**
     * 删除文件
     *
     * @param fileName 文件名
     * @param path     文件所在的路径(相对路径) "excel\\"
     */
    public static void deleteFile(String fileName, String path) {
        String filePath = TOMCAT_PATH + path + fileName;
        File file = new File(filePath);
        try {
            file.delete();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过 Token 解析出用户 id
     *
     * @return InstitutionId
     */
    public static String getIdByToken() {
        String token = String.valueOf(SecurityUtils.getSubject().getPrincipal());
        Institution institution = new TokenUtils().validationToken(token);
        return institution.getInstitutionId();
    }

    /**
     * 将 CertificateTmp 类型的实体类转化为 Certificate 类型
     *
     * @param data CertificateTmp
     * @return {@link Certificate}
     */
    public static Certificate certificateTmp2Certificate(CertificateTmp data) {
        Certificate res = new Certificate();
        try {
            BeanUtils.copyProperties(res, data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }

    /**
     * 获取当前的时间戳  yyyy-MM-dd hh:mm:ss
     *
     * @return String
     */
    public static String getCurrentDate_YMD_hms() {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return format.format(date);
    }

    public static String getCurrentDate_YMD() {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        return format.format(date);
    }


    /**
     * 身份证图片 OCR扫描
     *
     * @param imgPath 图片网址
     * @param side    face / back
     * @return String
     */
    public static JSONObject ocrIdCard(String imgPath, String side) {
        String host = "http://dm-51.data.aliyun.com";
        String path = "/rest/160601/ocr/ocr_idcard.json";
        String appcode = Secret.appCode;
        String method = "POST";

        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "APPCODE " + appcode);
        //根据API的要求，定义相对应的Content-Type
        headers.put("Content-Type", "application/json; charset=UTF-8");

        Map<String, String> querys = new HashMap<>();

        //configure配置
        JSONObject configObj = new JSONObject();
        configObj.put("side", side);

        String config_str = configObj.toString();

        // 拼装请求body的json字符串
        JSONObject requestObj = new JSONObject();
        JSONObject res_obj = new JSONObject();
        requestObj.put("image", imgPath);
        if (configObj.size() > 0) {
            requestObj.put("configure", config_str);
        }
        String bodys = requestObj.toString();
        try {
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            int stat = response.getStatusLine().getStatusCode();
            if (stat != 200) {
                throw new OCRFailedException();
            }
            String res = EntityUtils.toString(response.getEntity());
            res_obj = JSON.parseObject(res);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res_obj;
    }

    /**
     * 实名制核验
     *
     * @param cardNo   身份证
     * @param realName 名字
     * @return boolean
     */
    public static boolean verify(String cardNo, String realName) {
        int errorCode = -1;
        String host = "https://zid.market.alicloudapi.com";
        String path = "/idcard/VerifyIdcardv2";
        String method = "GET";
        String appcode = Secret.appCode;
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "APPCODE " + appcode);
        Map<String, String> querys = new HashMap<>();
        querys.put("cardNo", cardNo);
        querys.put("realName", realName);


        try {
            HttpResponse response = HttpUtils.doGet(host, path, method, headers, querys);
            System.out.println(response.toString());
            //获取response的body
            String entity = EntityUtils.toString(response.getEntity());
            JSONObject jsonObject = JSONObject.parseObject(entity);
            errorCode = (int) jsonObject.get("error_code");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return errorCode == 0;
    }

    /**
     * String 转 Date
     *
     * @param str 时间 String
     * @return Date
     */
    public static Date String2Date(String str) {
        DateFormat fm = new SimpleDateFormat("yyyyMMdd");
        Date res = null;
        try {
            res = fm.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return res;
    }

    public static String getFileHash(Certificate cert){
        StringBuilder buffer = new StringBuilder();
        buffer.append("/");
        buffer.append(cert.getUid());
        buffer.append("/");
        buffer.append(cert.getName());
        buffer.append("/");
        buffer.append(cert.getInstitution());
        buffer.append("/");
        buffer.append(cert.getSex());
        buffer.append("/");
        buffer.append(cert.getUserId());
        buffer.append("/");
        buffer.append(cert.getBirth());
        buffer.append("/");
        buffer.append(cert.getMajor());
        buffer.append("/");
        buffer.append(cert.getCertId());
        buffer.append("/");
        buffer.append(cert.getAdmissionDate());
        buffer.append("/");
        buffer.append(cert.getGraduationDate());
        buffer.append("/");
        buffer.append(cert.getAcademy());
        buffer.append("/");
        buffer.append(cert.getIssueDate());
        buffer.append("/");
        buffer.append(cert.getCertType());
        buffer.append("/");
        buffer.append(2);
        String str = buffer.toString();
        return HashUtil.md5(str);
    }

}
